package com.hlf.common.utils;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.hlf.common.constants.Constants;
import com.hlf.common.constants.FileConstants;
import com.hlf.common.exception.BusinessException;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

/**
 * 文件操作工具类
 *
 * @author shuliangxing
 * @date 2015-1-15上午9:48:33
 */
public class FileOperateUtil {
    /**
     * 实际名字
     */
    public static final String REALNAME = "realName";

    /**
     * 存储名字
     */
    public static final String STORENAME = "storeName";

    /**
     * 存储路径
     */
    public static final String STOREPATH = "storePath";

    /**
     * 大小,单位B
     */
    public static final String SIZE = "size";

    /**
     * 文件后缀
     */
    public static final String SUFFIX = "suffix";

    /**
     * contentType
     */
    public static final String CONTENTTYPE = "contentType";

    /**
     * 创建时间
     */
    public static final String CREATETIME = "createTime";

    /**
     * 默认上传目录
     */
    public static final String DEFAULT_UPLOADDIR = "upload";

    /**
     * 模板下载目录
     */
    // public static final String DOWNLOADDIR = "template/";

    // private static final Logger logger =
    // Logger.getLogger(FileOperateUtil.class);

    /**
     * 将上传的文件进行重命名，采用uuid防止猜测文件名(去掉横杠)
     *
     * @param name 原始文件名（包括文件后缀）
     * @return
     */
    public static String rename(String name) {
        String fileName = UUID.randomUUID().toString();
        fileName = fileName.replaceAll("-", "");
        if (name.indexOf(".") != -1) {
            fileName += name.substring(name.lastIndexOf("."));
        }
        return fileName;
    }

    /**
     * 压缩后的文件名
     *
     * @param name
     * @return
     */
    public static String zipName(String name) {
        String prefix = "";
        if (name.indexOf(".") != -1) {
            prefix = name.substring(0, name.lastIndexOf("."));
        } else {
            prefix = name;
        }
        return prefix + ".zip";
    }

    /**
     * 获取文件名后缀
     *
     * @param name
     * @return
     * @author shuliangxing
     * @date 2016年7月26日 上午11:20:54
     */
    public static String getFileSuffix(String name) {
        if (name.lastIndexOf(".") != -1) {
            return name.substring(name.lastIndexOf(".") + 1);
        }
        return "";
    }

    /**
     * 文件批量上传<br>
     * 把文件按分类和日期保存到服务器,最终路径为:服务器上传跟路径+文件分类路径+yyyy/MM/dd/
     *
     * @param basePath 服务器上传跟路径
     * @param typePath 文件分类路径
     * @param attrName 文件属性名称,等于null时上传全部文件
     * @param maxSize  允许上传文件的最大大小，单位B,为null时表示没有大小限制
     * @param minCount 允许上传文件的最小数量，等于null时表示没有限制
     * @param maxCount 允许上传文件的最大数量，等于null时表示没有限制
     * @param request
     * @return 保存信息
     * @throws IOException io异常
     * @author shuliangxing
     * @date 2017年3月30日 下午3:13:51
     */
    public static List<Map<String, Object>> upload(String basePath, String typePath, String attrName, Long maxSize,
                                                   Integer minCount, Integer maxCount, HttpServletRequest request) throws IOException {
        List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
        Date date = new Date();

        MultipartHttpServletRequest mRequest;
        if (!(request instanceof MultipartHttpServletRequest)) {
            throw new BusinessException("Http\"Content-Type\"必须为\"multipart/form-data\"格式");
        }
        mRequest = (MultipartHttpServletRequest) request;
        MultiValueMap<String, MultipartFile> fileMap = mRequest.getMultiFileMap();

        // 上传路径后面部分
        String sufPath = typePath + "/" + getUploadPathByDate(date);
        // 如果服务器上传跟路径为空则使用默认路径
        if (StringUtils.isEmpty(basePath)) {
            basePath = DEFAULT_UPLOADDIR;
        }

        // 如果服务器上传跟路径不是绝对路径("/"开头或盘符开头如“D:\”),则把文件存储到项目根目录下
        if (!basePath.startsWith("/") && !basePath.startsWith("\\") && !basePath.contains(":")) {
            basePath = request.getSession().getServletContext().getRealPath(basePath);
        }

        // 实际上传途径
        String realPath = basePath + "/" + sufPath;
        File file = new File(realPath);

        Iterator<String> it = null;
        Iterator<String> sizeIt = null;
        if (attrName != null) {
            List<String> l = new ArrayList<String>();
            l.add(attrName);
            it = l.iterator();
            sizeIt = l.iterator();
        } else {
            // 上传全部
            it = fileMap.keySet().iterator();
            sizeIt = fileMap.keySet().iterator();
        }

        // 文件数量
        int fileCount = 0;
        // 如果文件大小有限制，先判断文件大小是否满足
        if (maxSize != null) {
            while (sizeIt.hasNext()) {
                List<MultipartFile> fileList = fileMap.get(sizeIt.next());
                if (fileList == null || fileList.isEmpty()) {
                    continue;
                }

                fileCount = fileCount + fileList.size();
                for (MultipartFile mFile : fileList) {
                    if (!mFile.isEmpty()) {
                        if (mFile.getSize() > maxSize) {
                            throw new BusinessException("上传文件的大小超出限制，最大值" + maxSize + "B");
                        }
                    }
                }
            }
        }

        if (minCount != null && fileCount < minCount) {
            throw new BusinessException("最少上传" + minCount + "个文件");
        }
        if (maxCount != null && fileCount > maxCount) {
            throw new BusinessException("最多上传" + maxCount + "个文件");
        }

        if (!file.exists()) {
            // 可能创建多级目录,mkdir()不能创建多级目录,如果父目录不存在会返回false
            file.mkdirs();
        }

        while (it.hasNext()) {
            Map<String, Object> map = null;
            List<MultipartFile> fileList = fileMap.get(it.next());
            if (fileList == null || fileList.isEmpty()) {
                continue;
            }

            for (MultipartFile mFile : fileList) {
                if (!mFile.isEmpty()) {
                    map = new HashMap<String, Object>();
                    String fileName = mFile.getOriginalFilename();

                    String storeName = rename(fileName);

                    file = new File(realPath, storeName);
                    mFile.transferTo(file);

                    // 固定参数值对
                    map.put(FileOperateUtil.REALNAME, fileName);
                    map.put(FileOperateUtil.STORENAME, storeName);
                    map.put(FileOperateUtil.STOREPATH, sufPath + storeName);
                    map.put(FileOperateUtil.SIZE, mFile.getSize());
                    map.put(FileOperateUtil.SUFFIX, getFileSuffix(fileName));
                    map.put(FileOperateUtil.CONTENTTYPE, mFile.getContentType());
                    map.put(FileOperateUtil.CREATETIME, date);

                    list.add(map);
                }
            }

        }
        return list;
    }

    /**
     * 下载
     *
     * @param request
     * @param response
     * @param storePathAndName 文件存储路径和名称
     * @param contentType
     * @param realName         前端显示的下载名称
     * @throws IOException
     */
    public static void download(HttpServletRequest request, HttpServletResponse response, String storePathAndName,
                                String contentType, String realName) throws IOException {
        response.setContentType("text/html;charset=UTF-8");
        request.setCharacterEncoding("UTF-8");
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;

        /*
         * String ctxPath = request.getSession().getServletContext()
         * .getRealPath("/") + Constants.PATH_TEMPLATE;
         */
        String downLoadPath = FileConstants.FILE_UPLOAD_PATH + storePathAndName;

        long fileLength = new File(downLoadPath).length();

        response.setContentType(contentType);
        response.setHeader("Content-disposition",
                "attachment; filename=" + new String(realName.getBytes("utf-8"), "ISO8859-1"));
        response.setHeader("Content-Length", String.valueOf(fileLength));

        bis = new BufferedInputStream(new FileInputStream(downLoadPath));
        bos = new BufferedOutputStream(response.getOutputStream());
        byte[] buff = new byte[2048];
        int bytesRead;
        while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
            bos.write(buff, 0, bytesRead);
        }
        bis.close();
        bos.close();
    }

    /**
     * 根据路径删除指定的目录或文件
     *
     * @param sPath 要删除的目录或文件
     * @return 删除成功返回 true，否则返回 false。
     */
    public static boolean DeleteFolder(String sPath) {
        boolean flag = false;
        File file = new File(sPath);
        // 判断目录或文件是否存在
        if (!file.exists()) { // 不存在返回 false
            return flag;
        } else {
            // 判断是否为文件
            if (file.isFile()) { // 为文件时调用删除文件方法
                return deleteFile(sPath);
            } else { // 为目录时调用删除目录方法
                return deleteDirectory(sPath);
            }
        }
    }

    /**
     * 删除单个文件
     *
     * @param sPath 被删除文件的文件名
     * @return 单个文件删除成功返回true，否则返回false
     */
    public static boolean deleteFile(String sPath) {
        boolean flag = false;
        File file = new File(sPath);
        // 路径为文件且不为空则进行删除
        if (file.isFile() && file.exists()) {
            file.delete();
            flag = true;
        }
        return flag;
    }

    /**
     * 删除目录（文件夹）以及目录下的文件
     *
     * @param sPath 被删除目录的文件路径
     * @return 目录删除成功返回true，否则返回false
     */
    public static boolean deleteDirectory(String sPath) {
        // 如果sPath不以文件分隔符结尾，自动添加文件分隔符
        if (!sPath.endsWith(File.separator)) {
            sPath = sPath + File.separator;
        }
        File dirFile = new File(sPath);
        // 如果dir对应的文件不存在，或者不是一个目录，则退出
        if (!dirFile.exists() || !dirFile.isDirectory()) {
            return false;
        }
        boolean flag = true;
        // 删除文件夹下的所有文件(包括子目录)
        File[] files = dirFile.listFiles();
        for (int i = 0; i < files.length; i++) {
            // 删除子文件
            if (files[i].isFile()) {
                flag = deleteFile(files[i].getAbsolutePath());
                if (!flag)
                    break;
            } // 删除子目录
            else {
                flag = deleteDirectory(files[i].getAbsolutePath());
                if (!flag)
                    break;
            }
        }
        if (!flag)
            return false;
        // 删除当前目录
        if (dirFile.delete()) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 按照日期得到日期文件夹路径,格式yyyy/MM/dd/
     *
     * @param date
     * @return 如:2015/04/29/
     */
    public static String getUploadPathByDate(Date date) {
        if (date == null) {
            date = new Date();
        }
        // 按照日期分文件夹保存,格式yyyy/MM/dd
        String datePath = DateUtil.getYearStr(date) + "/" + DateUtil.getMonthStr(date) + "/" + DateUtil.getDayStr(date)
                + "/";

        return datePath;
    }

}
